package com.qingyun.web.security.provider;


import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;

import com.qingyun.common.constant.Constants;
import com.qingyun.common.core.domain.model.TiktokShopVo;
import com.qingyun.common.core.redis.RedisCache;
import com.qingyun.common.enums.SysUserType;
import com.qingyun.security.enums.App;
import com.qingyun.security.enums.LoginType;
import com.qingyun.security.exception.CaptchaAuthoException;
import com.qingyun.security.model.shop.AppLoginUser;
import com.qingyun.security.model.shop.AuthoAppConnect;

import com.qingyun.security.provider.AbstractUserDetailsAuthenticationProvider;
import com.qingyun.shop.domain.TiktokShop;
import com.qingyun.shop.domain.TiktokUserProxy;
import com.qingyun.shop.domain.TiktokUserShop;
import com.qingyun.shop.mapper.TiktokUserProxyMapper;
import com.qingyun.shop.mapper.TiktokUserShopMapper;
import com.qingyun.shop.service.ITiktokProxyService;
import com.qingyun.shop.service.ITiktokShopService;
import com.qingyun.web.security.service.UserDetailsServiceImpl;
import com.qingyun.web.security.token.WxMiniAppAuthenticationToken;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;

import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author dangyonghang
 * 小程序账号密码登陆
 */
@Component
@AllArgsConstructor
@Slf4j
public class MiniAppAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {


    private UserDetailsServiceImpl userDetailsService;

    private WxMaService wxMaService;

    private PasswordEncoder passwordEncoder;

    private ITiktokShopService tiktokShopService;

    private ITiktokProxyService tiktokProxyService;

    private TiktokUserShopMapper userShopMapper;

    private TiktokUserProxyMapper userProxyMapper;

    private MapperFacade mapperFacade;

    private RedisCache redisCache;

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, Authentication authentication) throws AuthenticationException {
		WxMiniAppAuthenticationToken tenantMiniAppAuthenticationToken=(WxMiniAppAuthenticationToken)authentication;
        if ( tenantMiniAppAuthenticationToken.getLoginType().getType().equals(LoginType.PASSWORD.getType())) {
            if (authentication.getCredentials() == null) {
                log.debug("密码为null");
                throw new BadCredentialsException("账号密码错误");
            } else {
				String presentedPassword = authentication.getCredentials().toString();
				if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
					log.debug("密码错误");
					throw new BadCredentialsException("账号密码错误");
				}
            }
        }
        String wxcode =  tenantMiniAppAuthenticationToken.getWxcode();
        if (wxcode  == null) {
            log.debug("微信code为空");
            throw new BadCredentialsException("登陆code不能为空");
        }
		AppLoginUser appLoginUser=(AppLoginUser)userDetails;
             AuthoAppConnect appConnect;
            WxMaJscode2SessionResult sessionInfo=null;
            try{
                sessionInfo = wxMaService.getUserService().getSessionInfo(wxcode);
                appConnect=userDetailsService.loadUserByAppIdAndBizUserId(App.MINIAPP, sessionInfo.getOpenid());
            } catch(WxErrorException we){
                throw new BadCredentialsException("微信登陆错误");
            } catch (UsernameNotFoundException ue){
                  appConnect=new AuthoAppConnect();
                  appConnect.setOpenId(sessionInfo.getOpenid());
                  appConnect.setUnionId(sessionInfo.getUnionid());
                  appConnect.setUserId(appLoginUser.getSysUser().getUserId());
                  appConnect.setEntryType(2);
                  appConnect.setUserType(App.MINIAPP.value());
                  userDetailsService.insertUserIfNecessary(appConnect);
            }
            if(ObjectUtil.isNull(appConnect)){
                appConnect=userDetailsService.loadUserByAppIdAndBizUserId(App.MINIAPP, sessionInfo.getOpenid());
            }
            appLoginUser.setOpenId(appConnect.getOpenId());

    }

    @Override
    protected Authentication createSuccessAuthentication(Authentication authentication, UserDetails user) {
		AppLoginUser appLoginUser = (AppLoginUser) user;
       //todo 看是否需要把商户信息给到对象里 后期都是针对商户来查询的
		String userType = appLoginUser.getSysUser().getUserType();
		SysUserType sysUserType = SysUserType.selectType(userType);
		TiktokUserShop tiktokUserShop;
		switch (sysUserType){
			case PROXY:
				TiktokUserProxy tiktokUserProxy = userProxyMapper.selectOne(Wrappers.lambdaQuery(TiktokUserProxy.class)
					.select(TiktokUserProxy::getProxyId)
					.eq(TiktokUserProxy::getUserId, appLoginUser.getSysUser().getUserId()));
				appLoginUser.setProxy(tiktokProxyService.getVoById(tiktokUserProxy.getProxyId()));

				tiktokUserShop = userShopMapper.selectOne(Wrappers.lambdaQuery(TiktokUserShop.class)
					.select(TiktokUserShop::getShopId)
					.eq(TiktokUserShop::getUserId, appLoginUser.getSysUser().getUserId()));
				appLoginUser.setShop(tiktokShopService.getVoById(tiktokUserShop.getShopId()));
				break;
			case SHOP:
				tiktokUserShop = userShopMapper.selectOne(Wrappers.lambdaQuery(TiktokUserShop.class)
					.select(TiktokUserShop::getShopId)
					.eq(TiktokUserShop::getUserId, appLoginUser.getSysUser().getUserId()));
				appLoginUser.setShop(tiktokShopService.getVoById(tiktokUserShop.getShopId()));
				break;
		}
		WxMiniAppAuthenticationToken shopAuthenticationToken = new WxMiniAppAuthenticationToken(appLoginUser, authentication.getCredentials());
		shopAuthenticationToken.setDetails(authentication.getDetails());
        return shopAuthenticationToken;
    }

    @Override
    protected App getAppInfo() {
        return null;
    }

    @Override
    protected UserDetails retrieveUser(String username, Authentication authentication) {
		WxMiniAppAuthenticationToken authenticationToken = (WxMiniAppAuthenticationToken) authentication;
        if(authenticationToken.getLoginType().getType().equals(LoginType.PHONE.getType())){
			String phone = (String)authenticationToken.getPrincipal();
			String captcha = redisCache.getCacheObject(phone);
			String code = (String)authenticationToken.getCredentials();
			//验证验证码
			if (captcha == null)
			{
				throw new CaptchaAuthoException(500,"验证码不能为空");
			}
			if (!code.equalsIgnoreCase(captcha))
			{
				throw new CaptchaAuthoException(500,"验证码错误");
			}
			redisCache.deleteObject(phone);
		}
		UserDetails userDetails = userDetailsService.sysShopWxLoginUserNameOrPhone(username);
        return userDetails;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return WxMiniAppAuthenticationToken.class.isAssignableFrom(aClass);
    }
}
